op doesn't work with first #122
Comments
Can you provide a stack trace, and a copy of your Gemfile.lock? Also, what happens when you do: Course.where{starting_school_year == 2011}.first |
Actually I did some more testing and it seems it's not 'first' that gives the error, but 'empty?', 'any?', and the like. The strange thing is that after I get an error on 'empty?', 'first' will also give the same error, until I quit the console. And it works the same in 1.0.0 and 0.9.5, I was mislead by the fact that 'first' worked fine after I switched to 1.0.0 and restarted the console. Course.where{starting_school_year == 2011}.empty? works fine. Here's the stack trace for 'Course.where{starting_school_year.op('=', 2011)}.empty?' in 1.0.1: TypeError: Cannot visit Arel::Nodes::InfixOperation And the Gemfile.lock: GEM PLATFORMS DEPENDENCIES Thanks, |
So, the issue would be coming from the attempt at a count, when asking for
I do notice there's an "and" in your SQL though. Is it possible you have something in a default scope that might be causing issues? What do you get from: Course.where{starting_school_year == 2011}.to_sql |
Course.where{starting_school_year == 2011}.to_sql gives "SELECT I don't have a default scope on this model. So I don't know where the 'and' could come from. Any other tests I can run? |
I tried it with some other models and other attributes, and it's the same for all of them. It starts to look like a conflict with one of the other gems. I'll try to remove some of them and see if it fixes it. |
It almost has to be. Taking a look at the ARel source: https://github.com/rails/arel/blob/master/lib/arel/visitors/to_sql.rb#L460-467 You can see that it most definitely does know how to visit. |
I removed all the gems that were not requested directly by rails and mysql2, and I was still getting the same error. Then I removed everything and reinstalled rails and all the gems, and still the same. So then I put a few trace messages in the 'visit' function that's raising the error. I ran the line: User.where{username.op('=', 'test')}.count Here's what I get right before the error:
So the problem is that the dispatch method for Arel::Nodes::InfixOperation in the hash is not visit_Arel_Nodes_InfixOperation, but visit_Arel_Nodes_Node. Any idea who's setting it? Here's the whole hash:
|
Never mind that, it seems it's set in the rescue part of 'visit', in an earlier call, when the original send failed. So the question is why the send fails.
|
@octavpo, I'm sorry, but I really don't know what to say. I have tried to duplicate the issue, and failed. Unless we can work up a failing spec or something I can go on, I'm not sure the issue is even mine to fix. :( |
One thing that might explain why you're not getting the error is that I'm using mysql, maybe you're using something else? I did a little more tracing of Arel::Visitor::visit, looking at what object it's called on, and here's what happens: there are two attempts to build the relation. On the first attempt the visit to node Arel::Nodes::InfixOperation is called on a Arel::Visitors::DepthFirst object.
This one doesn't have a 'visit_Arel_Nodes_InfixOperation' method, so the rescue part in 'visit' looks for an ancestor and finds 'visit_Arel_Nodes_Node'. Which succeeds but does nothing. So the first attempt fails and then on the second attempt the visit to node Arel::Nodes::InfixOperation is called on a ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::BindSubstitution object.
Which does have a 'visit_Arel_Nodes_InfixOperation' since it inherits from Arel::Visitors::MySQL, but the first visit replaced it with 'visit_Arel_Nodes_Node' in the dispatch hash, so it fails again. So I tried to remove the last two lines dispatch[object.class] = dispatch[superklass]
retry from Arel::Visitor::visit, and it works, now the second attempt succeeds. I don't know why Arel::Visitors::DepthFirst comes into play for me and not for you, maybe it's mysql or maybe I have something else that gets in between. For now I can avoid it by using 'exists?' instead of 'empty?', or removing those lines if I really need a count function. Thanks, |
Try adding this to ARel's depth_first.rb: def visit_Arel_Nodes_InfixOperation o
visit o.left
visit o.operator
visit o.right
end |
Yes that works. So it's a bug in Arel? Why weren't you getting it? Thanks, |
The test suite runs against sqlite3. I guess the depth-first visitor isn't needed in that case. I'll submit a pull request to ARel with the fix. Doing a mention to @tenderlove so he'll know it's coming in advance. ❤️ tenderlove |
Hm. Never mind. I see the following in the code:
Sorry for the noise, @tenderlove. |
@octavpo what that means is that the visit_Arel_Nodes_InfixOperation was already defined in that class. That makes me wonder why redefining it fixed your problem. |
I don't have that alias line in the released arel 3.0.2 I have installed. Maybe they added it later? I tried it instead of your fix and it works too. Actually even an empty function seems to work, because it just prevents Visitor::visit to replace the dispatch function. So I'm not sure what's with DepthFirst. If it's supposed to build something it probably still fails, since it's still the second visit that succeeds. |
DepthFirst visitors are there for the ability to iterate through an AST in the same way you might an array. And sure enough, looks like it was added in the past 2 months or so. I could maybe do another conditional monkeypatch in compat.rb, I suppose. |
Fixes Casecommons#101 by making sure Arel alias is in place Based on a similar fix for activerecord-hackery/squeel#122
Course.where{starting_school_year.op('=', '2011')}.first
gives a TypeError: Cannot visit Arel::Nodes::InfixOperation in version 1.0.1, although it works fine in 1.0.0.
Thanks,
Octav
The text was updated successfully, but these errors were encountered: