home icon contact icon rss icon

with_scope & joins

Dans rails, on trouve des pépites et with_scope en est une. Une vieille pépite et toujours pas finie, je serais tenté de dire.

Par exemple, il ne tient pas compte de la clause :order.

De mon côté, j’ai besoin d’un ordre précis pour faire le merge de mes jointures.

Prenons l’exemple suivant :

class Dumb
  class << self

    def foo_bar
      with_scope(:find => { :join => "INNER JOIN bar ON bar.id=foo.bar_id"}) do
        want_foo
      end
    end

    def want_foo
        with_scope(:find => { :join => "INNER JOIN foo ON foo.id=dump.foo_id"}) do
        # do your stuff
        ...
        end
    end

  end
end
 ... INNER JOIN bar ON bar.id=foo.bar_id INNER JOIN foo ON foo.id=dump.foo_id ...
... ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'foo.bar_id' ..

On souhaite avoir l’ordre inversé genre :

 ... INNER JOIN foo ON foo.id=dump.foo_id INNER JOIN bar ON bar.id=foo.bar_id  ...

Voici la solution :

    ...
    do_reverse_merge_joins do
      def foo_bar
        with_scope(:find => { :join => "INNER JOIN bar ON bar.id=foo.bar_id"}) do
          want_foo
        end
      end
    end
    ...

et le patch ou l’extension comme vous voulez (testé pour rails 2.3)

ActiveRecord::Base.class_eval do
  class << self
    def merge_joins_with_reverse(*joins)
      merge_joins_without_reverse(reverse_merge_joins? ? joins.reverse : joins)
    end
    alias_method_chain :merge_joins, :reverse

    def do_reverse_merge_joins(&block)
      set_reverse_merge_joins
      result = yield
      reset_reverse_merge_joins
      result
    end

    def reset_reverse_merge_joins
      set_reverse_merge_joins(nil)
    end

    def set_reverse_merge_joins(value = true)
      Thread.current[:"#{self}_reverse_merge_joins"] = value
    end

    def reverse_merge_joins?
      Thread.current[:"#{self}_reverse_merge_joins"]
    end

  end
end

Laissez un commentaire