Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 756
Titas Avatar asked Jun 15 '11 13:06

Titas


2 Answers

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.

like image 76
Vasiliy Ermolovich Avatar answered Sep 21 '22 03:09

Vasiliy Ermolovich


I was able to circumvent this problem by defining to_s method for my class

class CustomItem
  def to_s
    custom_id
  end
end

And tricking Arel Visitor to treat my class as Fixnum

Arel::Visitors::Visitor::DISPATCH[CustomItem] = 'visit_Fixnum'

Worked with Rails 3.2.13.

For string-like value you should probably mimick String and use visit_String.

like image 23
Petr ''Bubák'' Šedivý Avatar answered Sep 21 '22 03:09

Petr ''Bubák'' Šedivý