2

I'm using rails 4 with postgres db, and im trying out array. But I can't get my query to work.

I have this so far:

@contacts = current_firm.contacts.order(:name)

and would like to add a params[:show] to the query, so it only shows the records with e.g. 'place' in the contactType column. if the url is contacts?show=place.

I really hope you can help, because I have tried to figure this out for hours now.

Schema:

create_table "contacts", force: true do |t|
  t.integer  "firm_id"
  t.string   "contactType",                 array: true
  t.string   "name"
  t.string   "adress"
  t.integer  "zipcode"
  t.string   "town"
  t.string   "country",     default: "DK"
  t.integer  "cvr"
  t.string   "email"
  t.string   "contact"
  t.string   "phone"
  t.string   "cellPhone"
  t.string   "website"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.boolean  "deleteFlag",  default: false
end

Console dump of Contact.all

#<ActiveRecord::Relation 
  [#<
    Contact id: 7, 
    firm_id: 5, 
    contactType: ["customer", "place"], 
    name: "PA Syd", 
    adress: "", 
    zipcode: nil, 
    town: "", 
    country: "DK", 
    cvr: nil, email: "", 
    contact: "Lars Opstrup", 
    phone: "", 
    cellPhone: nil, 
    website: "", 
    created_at: "2013-06-28 13:29:18", 
    updated_at: "2013-06-28 13:29:18", 
    deleteFlag: false
  >, 
  #<
    Contact id: 1, 
    firm_id: 5, 
    contactType: ["place"], 
    name: "Mads Ellesgaard", 
    adress: "", 
    zipcode: 6400, 
    town: "Soenderborg", 
    country: "DK", 
    cvr: nil, 
    email: "[email protected]", 
    contact: "", 
    phone: "", 
    cellPhone: nil, 
    website: "", 
    created_at: "2013-06-28 11:58:58", 
    updated_at: "2013-06-29 09:35:39", 
    deleteFlag: false
  >
]>

3 Answers 3

6

You want to use the postgresql operator && (array overlap operator) to see if any values overlap between the params hash and the data in the table.

@contacts = current_firm.contacts.order(:name).where("ARRAY[?]::varchar[] && contactType", params[:show])

The params hash should be of type text[], while the contactType record is of type varchar[], so you need to cast the incoming params hash to match that of the contactType record for postgres to not throw an error.

See the docs here: http://www.postgresql.org/docs/9.2/static/functions-array.html

You may also want to check out the postgres_ext gem if you have many of these types of queries, although for this use case it might be excessive overhead: https://github.com/dockyard/postgres_ext/blob/master/docs/querying.md

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much! It was a great help, I just had to rename my column from contactType to contact_type and it works.
3
@contacts = current_firm.contacts.where("'?' = ANY (contactType)", params[:show]).order(:name)

I didn't test it, but it should work.

7 Comments

It turns this out: PG::Error: ERROR: column "customer" does not exist LINE 1: ...eteFlag" = 'f' AND "contacts"."firm_id" = $1 AND (customer =... ^ : SELECT "contacts".* FROM "contacts" WHERE "contacts"."deleteFlag" = 'f' AND "contacts"."firm_id" = $1 AND (customer = ANY (contactType)) ORDER BY "contacts".name ASC
if i do @contacts = current_firm.contacts.where("(contactType) = ANY '#{params[:show]}'").order(:name)
i get: PG::Error: ERROR: syntax error at or near "'customer'"
where("#{params[:show]} = ANY (contactType)") looks like it is susceptible to sql injection? maybe where("? = ANY (contactType)", params[:show]) would be better
in the generated sql AND (customer = ANY (contactType)) i believe customer needs to be single quoted? i.e. AND ('customer' = ANY (contactType)) - see coderwall.com/p/sud9ja
|
1
@contacts = current_firm.contacts.where.contains(contactType: [params[:show]]).order(:name)

see: https://viget.com/extend/searching-serialized-fields-in-rails-using-postgres-arrays

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.