2011-12-20 55 views
0

我在我的应用程序中有一个bazillion控制器,我想知道如何使用一些元编程来使维护更少。这是有效的,但它的eval形式的危险刺激:Eval alternative

def plural_action(method_name) 
    class_name = self.class.to_s.gsub(%r{^(\w*)Controller}) {|s| $1 } 
    @title = "#{method_name.to_s.titlecase} of #{class_name}" 
    eval "@q = #{class_name.singularize}.where(:client_id => current_user.client_id).search(params[:q])" 
    eval "@#{class_name.downcase} = @q.result(:distinct => true).paginate(:page => params[:page])" 
    eval "session[:query] = @#{class_name.downcase}.map(&:id)" 
    eval "respond_with(@#{class_name.downcase})" 
    end 

我可以做到这一点,而不使用eval?我已经修改了instance_variable_set,send和const_get,但目前还没有运气。

下面是我想要评估方法的一个示例。

def index 
    @title = "Index of Books" 
    @q = Book.where(:client_id => current_user.client_id).search(params[:q]) 
    @books = @q.result(:distinct => true).paginate(:page => params[:page]) 
    session[:query] = @books.map(&:id) 
    respond_with(@books) 
    end 
+0

[decent_exposure](https://github.com/voxdolo/decent_exposure)gem可能会让你成为那里的一部分,尽管它不会完全解决问题。 – 2011-12-20 12:08:03

回答

3

有一个宏伟的方法constantize其中把一个串入常数(其中类类型是一个例子)它代表。考虑到这一点,我认为你可以重写你的方法为:

def plural_action(method_name) 
    class_name = self.class.to_s.gsub(%r{^(\w*)Controller}) {|s| $1 } 
    @title = "#{method_name.to_s.titlecase} of #{class_name}" 
    @q = class_name.singularize.constantize.where(:client_id => current_user.client_id).search(params[:q]) 
    self.instance_variable_set("@#{class_name.downcase}", @q.result(:distinct => true).paginate(:page => params[:page])) 
    session[:query] = self.instance_variable_get("@#{class_name.downcase}").map(&:id) 
    respond_with(self.instance_variable_get("@#{class_name.downcase}")) 
end 
+0

哦,这很方便。但是,我需要能够设置实例变量。我会用期望的结果编辑我的问题。谢谢! – snowangel 2011-12-20 09:31:20

+0

@snowangel - 它看起来像'instance_variable_set' _应该做你想做的。我会编辑我的答案 - 但你说你已经试过了? – Chowlett 2011-12-20 09:36:29

+0

嗯,我试过了,但可能做错了,所以你的想法会非常有帮助。 – snowangel 2011-12-20 09:39:23

0
def plural_action(method_name) 
    class_name = self.class.to_s.gsub(%r{^(\w*)Controller}) {|s| $1 } 
    @title = "#{method_name.to_s.titlecase} of #{class_name}" 
    @q = class_name.singularize.constantize.where(:client_id => current_user.client_id).search(params[:q]) 
    instance_variable_set class_name.downcase, @q.result(:distinct => true).paginate(:page => params[:page]) 
    session[:query] = @q_result.map(&:id) 
    respond_with(@q_result) 
end 
+0

这会引发错误“不允许书籍作为实例变量名称”。 Chowlett的版本虽然工作。非常感谢答复! – snowangel 2011-12-20 09:44:26

0

你想使用inherited_resource宝石做这一切的吗?

+0

听起来很蠢,但是由于宝石的依赖关系,我的heroku slu size大小已经是77mb了。我尽可能不要添加更多! – snowangel 2011-12-20 15:11:01

+0

我认为Heroku将不得不重新评估100MB的限制。我的基本Rails 3.1应用程序也接近50MB。我宁愿让Heroku解决这个问题,而不是摆脱我的宝石。 – Amala 2011-12-20 18:17:41

+0

我同意。我最近为他们发布了一个支持票 - 如果我听到回复,会在这里添加评论。 – snowangel 2011-12-21 06:16:07