Adding new ARel visitors to resolve TypeError: Cannot visit ClassName

1,127 views
Skip to first unread message

Peter Brown

unread,
Jul 15, 2012, 10:01:38 AM7/15/12
to rubyonra...@googlegroups.com
Is there an approved way to add or register a new ARel visitor without adding it to the ARel source? Looking at the some of the source code it appears that new visitors are just hard coded as a new methods or aliases.

The reason I'm asking is because I get  "TypeError: Cannot visit ClassName" when I override reader methods with some sort of composed object (similar to Active Record's composed_of) and use that attribute in a uniqueness validation. 

Take the following for example:

class Cat < ActiveRecord::Base
  validates :name, :uniqueness => { :scope => [:breed] }

  def breed
    CatBreed.new(super)
  end
end

class CatBreed
  def initialize(breed)
    @breed = breed
  end

  def to_s
    @breed
  end
end

The above code will raise "TypeError: Cannot visit CatBreed" when I try to create a new cat unless I add a visitor method to Arel::Visitors::ToSql called visit_CatBreed:

class Arel::Visitors::ToSql
  def visit_CatBreed(value)
    quoted(value.to_s)
  end
end

I'm hoping there is a better way to deal with this problem, either with a less hacky ARel approach or something different all together.


Aaron Patterson

unread,
Jul 15, 2012, 1:50:01 PM7/15/12
to rubyonra...@googlegroups.com
On Sun, Jul 15, 2012 at 07:01:38AM -0700, Peter Brown wrote:
> Is there an approved way to add or register a new ARel visitor without
> adding it to the ARel source? Looking at the some of the source code<https://github.com/rails/arel/blob/master/lib/arel/visitors/to_sql.rb#L434-466> it
Doing this is fine for now. The way the AST is translated to SQL won't
change, so this will probably not break in the future.

> I'm hoping there is a better way to deal with this problem, either with a
> less hacky ARel approach or something different all together.

It seems like we should be using the underlying database value (the
attribute value rather than the return value of the method call) for the
unique constraint. I think this might be a bug. Jon, wdyt?

--
Aaron Patterson
http://tenderlovemaking.com/

Peter Brown

unread,
Jul 15, 2012, 3:43:26 PM7/15/12
to rubyonra...@googlegroups.com
Aaron,

Thanks for the reply. I played around with it a little and it seems like changing how the scope_value is retrieved in ActiveRecordmodule::Validationsclass::UniquenessValidator would fix the issue (though I'm not sure what sort of repercussions this would have elsewhere)

scope_value = record.send(scope_item)

to either of these

record[scope_item]
record.read_attribute(scope_item)

Jon Leighton

unread,
Jul 16, 2012, 3:36:39 PM7/16/12
to rubyonra...@googlegroups.com
>> I'm hoping there is a better way to deal with this problem, either with a
>> less hacky ARel approach or something different all together.
>
> It seems like we should be using the underlying database value (the
> attribute value rather than the return value of the method call) for the
> unique constraint. I think this might be a bug. Jon, wdyt?

Yes, I agree. Who wants to create a patch? :)

--
http://jonathanleighton.com/


Peter Brown

unread,
Jul 16, 2012, 8:49:26 PM7/16/12
to rubyonra...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages