ranked-model
ranked-model copied to clipboard
RankedModel::InvalidField for perfectly valid ActiveRecord instance
I'm seeing some weird RankedModel
behavior:
ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-darwin12.3.0]
rails (4.0.0.rc1)
ranked-model (0.2.0)
class Column < ActiveRecord::Base
include RankedModel
ranks :display, with_same: :board_id
belongs_to :board
scope :ordered, -> { rank(:display) }
end
$ b = Board.create
=> #<Board id: 2, title: nil, data: {}, created_at: "2013-05-18 06:25:41", updated_at: "2013-05-18 06:25:41">
$ c1 = Column.create(title: 'c1', board: b)
=> #<Column id: 10, title: "c1", display: 0, board_id: 2, data: {}, created_at: "2013-05-18 06:26:04", updated_at: "2013-05-18 06:26:04">
$ c2 = Column.create(title: 'c2', board: b)
RankedModel::InvalidField: No field called "board_id" found in model
If I pry
what's happening, I see the following:
$ c1 = Column.create(title: 'c1', board: b)
$ instance.respond_to?(ranker.with_same)
=> true
$ instance
=> #<Column id: nil, title: "c1", display: 0, board_id: 2, data: {}, created_at: nil, updated_at: nil>
$ exit
=> #<Column id: 10, title: "c1", display: 0, board_id: 2, data: {}, created_at: "2013-05-18 06:26:04", updated_at: "2013-05-18 06:26:04">
$ c2 = Column.create(title: 'c2', board: b)
$ instance.respond_to?(ranker.with_same)
=> true
$ instance
=> #<Column id: nil, title: "c2", display: 0, board_id: 2, data: {}, created_at: nil, updated_at: nil>
$ exit
# Column Load (0.9ms) SELECT "columns"."id", "columns"."display" FROM "columns"
# WHERE "columns"."board_id" = 2 AND "columns"."display" = 0
# ORDER BY "columns"."id" ASC LIMIT 1
$ instance.respond_to?(ranker.with_same)
=> false
$ instance
=> #<Column id: 10, display: 0>
$ exit
RankedModel::InvalidField: No field called "board_id" found in model
What seems to be happening is that on creating the second column
, it actually checks the other columns to see if things need to shift around. However, the query (which I added in the stack trace above) only selects the id
and display
fields, leaving out the board_id
field. This in return results in instance.respond_to?(ranker.with_same)
failing.
This seems like too big a bug to have gone unnoticed for so long, so I fully expect the problem to be on my end, but I can't figure out what could be causing this. I am not doing anything special.
For completeness sake, here's the full (unmodified) backtrace:
2.0.0 (main):0 > b = Board.create
(0.2ms) BEGIN
SQL (6.6ms) INSERT INTO "boards" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"
[["created_at", Sat, 18 May 2013 06:41:50 UTC +00:00], ["updated_at", Sat, 18 May 2013 06:41:50 UTC +00:00]]
(1.3ms) COMMIT
=> #<Board id: 5, title: nil, data: {}, created_at: "2013-05-18 06:41:50", updated_at: "2013-05-18 06:41:50">
2.0.0 (main):0 > c1 = Column.create(title: 'c1', board: b)
(0.3ms) BEGIN
Column Load (1.1ms) SELECT "columns"."id", "columns"."display" FROM "columns" WHERE
"columns"."board_id" = 5 AND "columns"."display" = 0 ORDER BY "columns"."id" ASC LIMIT 1
SQL (1.0ms) INSERT INTO "columns" ("board_id", "created_at", "title", "updated_at") VALUES ($1, $2, $3, $4)
RETURNING "id" [["board_id", 5], ["created_at", Sat, 18 May 2013 06:41:52 UTC +00:00], ["title", "c1"],
["updated_at", Sat, 18 May 2013 06:41:52 UTC +00:00]]
(1.3ms) COMMIT
=> #<Column id: 13, title: "c1", display: 0, board_id: 5, data: {}, created_at: "2013-05-18 06:41:52",
updated_at: "2013-05-18 06:41:52">
2.0.0 (main):0 > c2 = Column.create(title: 'c2', board: b)
(0.2ms) BEGIN
Column Load (0.6ms) SELECT "columns"."id", "columns"."display" FROM "columns" WHERE
"columns"."board_id" = 5 AND "columns"."display" = 0 ORDER BY "columns"."id" ASC LIMIT 1
(0.3ms) ROLLBACK
RankedModel::InvalidField: No field called "board_id" found in model
from /Users/Jean/.rbenv/versions/2.0.0-p195/gemsets/flow/gems/ranked-model-0.2.0/
lib/ranked-model/ranker.rb:47:in `validate_ranker_for_instance!'
Adding the with_same
columns to the select
optimization from ranker.rb#L226 solved the issue and everything seems to be working still. This helps me to at least continue until you find the time to comment on this so we can possibly find out what the real cause is (because I still don't believe this has never come up before, so I expect it to be some edge case on my end).
+ _select = [instance_class.arel_table[:id], instance_class.arel_table[ranker.column]]
+ _select.concat [ranker.with_same].flatten if ranker.with_same
- _finder.order(instance_class.arel_table[ranker.column].asc).select([instance_class.arel_table[:id], instance_class.arel_table[ranker.column]])
+ _finder.order(instance_class.arel_table[ranker.column].asc).select(_select)
Meant to post this issue sooner. Was able to fix this on my rails 4 branch. See my commit here https://github.com/mikeycgto/ranked-model/commit/fb0795b70563f0ae0da96c83fc053b288849afe2
@JeanMertz your fix seems to make sense - That was all you needed to change for Rails 4? @mikeycgto had to update .all
method calls to .load
and such.
I'm hoping for time this week to some up with a testing solution for testing against rails 3 and 4 in the gem.
@mixonic I do get deprecation warnings in my logs regarding the .all
calls. If you'd want to get rid of them, I'd swap .all
for .to_a
. That one is cross-version compatible instead of the Rails 4 only .load
.
Other than that, things seem to work fine.
Although one thing I noticed is #{ranker}_position
being nil whenever I want to get the relative position. I am not sure if this ever was intended to be used like this (the setter #{ranker}_position=
works correctly). I haven't had a real need for it though, so haven't really investigated yet.
@mixonic I believe we can make those .all
calls to be .to_a
calls. This should give rails 3 and 4 support.
same problem here on rails4 RC2
@mikeycgto's commit worked for me, lets get that merged! :+1:
Closing due to age. Perhaps this was fixed?