2011-12-20 5 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, но пока не повезло.

Вот пример того, что я хотел бы использовать для метода eval.

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

Драгоценный камень [приличная_экспозиция] (https://github.com/voxdolo/decent_exposure) может помочь вам в этом, хотя он полностью не решит проблему. –

ответ

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

+0

@snowangel - похоже, что 'instance_variable_set' _should_ делает то, что вы хотите. Я отредактирую свой ответ, но вы говорите, что попробовали? – Chowlett

+0

Ну, я попробовал, но, возможно, сделал это неправильно, так что ваши мысли были бы невероятно полезными. – snowangel

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

Это заставило ошибку «книги» не разрешено в качестве имени переменной экземпляра ». Тем не менее, была версия Хоулетта. Большое спасибо за ответ, хотя !. – snowangel

0

Вы думали об использовании inherited_resource драгоценный камень, чтобы сделать все это для вас?

+0

Звучит глупо, но размер моего героя-пули уже составляет 77 мб из-за зависимости от драгоценных камней. Я стараюсь, где можно, не добавлять больше! – snowangel

+0

Я думаю, что Героку придется переоценить предел 100 мб. Мое основное приложение Rails 3.1 также находится около 50 МБ. Я бы предпочел, чтобы Хероку исправился, хотя избавился от моих драгоценных камней. – Amala

+0

Согласен. Я недавно опубликовал им билет поддержки - добавлю здесь комментарий, если я услышу ответ. – snowangel