ransack icon indicating copy to clipboard operation
ransack copied to clipboard

Incorrect type definition in case of models with identical attributes names

Open mkalmykov opened this issue 8 years ago • 3 comments

Hi, guys!

I have the following models:

ActiveRecord::Schema.define do
  create_table "apartments", force: true do |t|
    t.integer  "house_id",   null: false
    t.integer  "number",     null: false
  end

  create_table :houses, force: true do |t|
    t.string   "number",     null: false
  end
end

I want to filter apartments by house numbers:

Apartment.ransack({ house_number_eq: 'д.38г' }).result

It produces the following query:

SELECT "apartments".* FROM "apartments" LEFT OUTER JOIN "houses" ON "houses"."id" = "apartments"."house_id" WHERE "houses"."number" = 0

And the following error, because instead of WHERE "houses"."number" = 'д.38г' I receive WHERE "houses"."number" = 0:

ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR:  operator does not exist: character varying = integer
LINE 1: ..."."id" = "apartments"."house_id" WHERE "houses"."number" = 0
                                                                    ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.

Seems that if we have related model with identical attributes names, but different types, ransack may define the type of attribute incorrectly. For example, in this case number attribute's type in House model is string, but it considers it as integer, like in Apartment model.

If I rename an attribute in one of the models, everything goes fine.

Here is a gist with test.

Additional info:

Ruby 2.4.0 Active Record 5.0.6 Arel 7.1.4 As for Ransack, I encountered this in 1.8.2 and also reproduced in 1.8.4.

mkalmykov avatar Oct 30 '17 13:10 mkalmykov

I had the same issue and had to come up with a workaround because I couldn't rename the column.

Having something like this:

ActiveRecord::Schema.define do
  create_table "properties", force: true do |t|
    t.integer  "country_id",   null: false
    t.integer  "code",     null: false
  end

  create_table :countries, force: true do |t|
    t.string   "code",     null: false
  end
end

What I did is create a ransacker on Countries' model with another name so the names dont collide, like so:

  ransacker :short_code do
    Arel.sql('countries.code')
  end

ffiebig avatar May 18 '18 19:05 ffiebig

@ffiebig thank you so much it worked for me.

jean-francois-labbe avatar Aug 30 '18 16:08 jean-francois-labbe

A documentation PR would be welcomed here from a community member.

scarroll32 avatar Jan 10 '20 23:01 scarroll32