Search code examples
ruby-on-railsalias-method-chain

Alias method chain in ruby calling itself


I am rewriting the controller render method, however, I want to use the old method when in the render_to_string method. These are my current codes:

def render_with_xhr(options = {}, extra_options = {}, xhr_check = true, &block)
  if xhr_check && request.xhr?
    template = render_to_string(options)
    render_without_xhr(:update) {|page| page.replace_html("#popup .dialog", template)}
  else
    render_without_xhr(options, extra_options, &block)
  end
end

alias_method_chain :render, :xhr

What happens is that since render_to_string makes use of render (presumably), I end up in an infinite loop. How can I make it fall back to the old method just for that line my new render method?

I tweaked the codes from the accepted answer, final code is below:

def render_to_string(options = {}, &block)
  render(options, {}, false, &block)
ensure
  response.content_type = nil
  erase_render_results
  reset_variables_added_to_assigns
end

def render_with_xhr(options = nil, extra_options = {}, xhr_check = true, &block)
  if xhr_check && request.xhr?
    template = render_to_string(options)
    render_without_xhr :update do |page|
      page.replace_html("#popup .dialog", template)
    end
  else
    render_without_xhr(options, extra_options, &block)
  end
end

alias_method_chain :render, :xhr

Solution

  • you could at line 2 pass some unique value to options hash, and then detect it in your code and remove

    def render_with_xhr(options = {}, extra_options = {}, xhr_check = true, &block)
      if xhr_check && request.xhr? && !options.delete(:bacon)
        template = render_to_string(options.merge(:bacon => true))
        render_without_xhr(:update) {|page| page.replace_html("#popup .dialog", template)}
      else
        render_without_xhr(options, extra_options, &block)
      end
    end
    
    alias_method_chain :render, :xhr
    

    like that :)