Search code examples
rubyruby-on-rails-3arelvisitor-pattern

Rails3 Arel visits to custom classes


I have a custom class, but I want to be able to pass it to Arel and let it resolve its queryable part.

module Custom
  class Item
    attr_accessor :name

    def initialize(name)
      self.name = name
    end
  end
end

custom_item = Custom::Item.new("Bill")
User.where(:name => custom_item)

is there anything I can define in custom_item, so it would understand that Arel wants name from it?

Currently I workaround with:

module Arel
  module Visitors
    class ToSql
      def visit_Custom_Item o
        "'#{o.name}'"
      end
    end
  end
end

Solution

  • I think it's not possible now. Let's try to figure out why.

    When you try to pass your custom object to the where method User.where(:name => custom_item) Arel try to call visit_YOUR_CLASS_NAME method (https://github.com/rails/arel/blob/master/lib/arel/visitors/visitor.rb#L15) but it fails. Then Arel try to call visit_+object.class.ancestors.find {|klass| respond_to?(DISPATCH[klass], true)} but it fails again because:

    irb(main):001:0> class Foo
    irb(main):002:1> end
    => nil
    irb(main):003:0> foo = Foo.new
    => #<Foo:0x261edc0>
    irb(main):004:0> foo.class.ancestors.map {|klass| p klass}
    Foo
    Object
    Kernel
    BasicObject
    => [Foo, Object, Kernel, BasicObject]
    

    and Arel doesn't have any of this names in this list https://github.com/rails/arel/blob/master/lib/arel/visitors/to_sql.rb#L394:

    alias :visit_ActiveSupport_Multibyte_Chars :quoted
    alias :visit_ActiveSupport_StringInquirer  :quoted
    alias :visit_BigDecimal                    :quoted
    alias :visit_Class                         :quoted
    alias :visit_Date                          :quoted
    alias :visit_DateTime                      :quoted
    alias :visit_FalseClass                    :quoted
    alias :visit_Float                         :quoted
    alias :visit_Hash                          :quoted
    alias :visit_NilClass                      :quoted
    alias :visit_String                        :quoted
    alias :visit_Symbol                        :quoted
    alias :visit_Time                          :quoted
    alias :visit_TrueClass                     :quoted
    

    Actually, I don't think it's a very useful feature but I've asked Aaron Patterson about this and if he'll like it I'll try to implement it.