Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

ActiveResource::Base.prefix isn't reset correctly when ActiveResource::Base.site is reset.

#1730

If you need to set the values for ActiveResource.site with a URI that includes a path, ActiveResource::Base.prefix will be wrong.

Consider this example. If you have an active resource called MyActiveResource (e.g.: )


class MyActiveResource < ActiveResource::Base
end

Setting a site value, and then another site value will produce the wrong ActiveResource::Base.prefix value, if the site url has a path.

See this example:


MyActiveResource.site = "http://www.example.com/app1"
# => "http://www.example.com/app1"
 MyActiveResource.prefix
# => "/app1/"
MyActiveResource.site = "http://www.example.com/app2"
# "http://www.example.com/app2"

MyActiveResource.prefix
# "/app1/"  <---- BUG ----

MyActiveResource.site.path
# => "/app2"  <-- Prefix above is wrong despite new, correct value of MyActiveResource.site.path

As you can see, even though you set a new site with a different path, the prefix method is not updated with the new site.path value, whereas it should be.

At first glance, this looks like it's because the first ActiveRecord::Base#prefix= call overrides the original prefix method with a new method, that retains the old value. Why does the prefix= override the prefix method with a new method??


      # Sets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>).
      # Default value is <tt>site.path</tt>.
      def prefix=(value = '/')
        # Replace :placeholders with '#{embedded options[:lookups]}'
        prefix_call = value.gsub(/:\w+/) { |key| "\#{options[#{key}]}" }

        # Clear prefix parameters in case they have been cached
        @prefix_parameters = nil

        # Redefine the new methods.
        code = <<-end_code
          def prefix_source() "#{value}" end
          def prefix(options={}) "#{prefix_call}" end                                     # <--- ????
        end_code
        silence_warnings { instance_eval code, __FILE__, __LINE__ }
      rescue
        logger.error "Couldn't set prefix: #{$!}\n  #{code}"
        raise
      end

Reported by Matthew Moore · January 11th, 2009 @ 02:53 AM

State: committed
Milestone: none
Assigned to: Rick Rick
Importance: none

Activity

  1. Matthew Moore
    Matthew Moore

    It seems odd to me that the prefix is stored in a method (by redefining a method when it's set), rather than a variable.

    Was there any method to this madness? Why it shouldn't just be stored in a class variable?

    January 11th, 2009 @ 03:36 AM

  2. Michael Koziarski
    Michael Koziarski
    • Milestone cleared.

    Short version is that class variables don't play nice with inheritance. So if you set it on ChildClass it overrides ParentClass

    January 12th, 2009 @ 05:25 AM

  3. Michael Koziarski
    Michael Koziarski
    • Assigned user changed from Michael Koziarski to Rick

    Assigning to rick as he uses ares, feel free to remove the 2.3 blocker if it's not immediately obvious how to fix it.

    February 1st, 2009 @ 02:11 AM

  4. Rick
    Rick

    Because #prefix has to take an options parameter. If you set it to something like "/projects/:project_id", the prefix method will look something like this:

    
    def prefix(options = {})
      "/projects/#{options[:project_id]}"
    end
    
    Message.prefix(:project_id => 1) # => "/projects/1"
    

    February 1st, 2009 @ 06:08 PM

  5. Rick
    Rick
    • State changed from new to committed

    I committed a fix to my rails fork, let me know if it works out.

    February 1st, 2009 @ 06:37 PM