This project is archived and is in readonly mode.

#1730 ✓committed
Matthew Moore

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

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

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

Comments and changes to this ticket

  • Matthew Moore

    Matthew Moore January 11th, 2009 @ 03:36 AM

    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?

  • Michael Koziarski

    Michael Koziarski January 12th, 2009 @ 05:25 AM

    • Milestone cleared.

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

  • Michael Koziarski

    Michael Koziarski February 1st, 2009 @ 02:11 AM

    • 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.

  • Rick

    Rick February 1st, 2009 @ 06:08 PM

    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"
    
  • Rick

    Rick February 1st, 2009 @ 06:37 PM

    • State changed from “new” to “committed”

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

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages