Ho un progetto su Ruby on Rails 4.1.4, utilizzando activeadmin 1.0.0.pre from git://github.com/activeadmin/activeadmin
, pg 0.17.1
, PostgreSQL 9.3Rails + ActiveAdmin - filtraggio con ransacker genera un errore PG :: SyntaxError: ERRORE: errore di sintassi o in prossimità ""
Nel progetto ho questi modelli:
class User has_one :account
class Account belongs_to :user has_many :project_accounts has_many :projects, :through => :project_accounts
class Project # the project has a boolean attribute 'archive' has_many :project_accounts
class ProjectAccount belongs_to :account belongs_to :project
Ho un compito di implementare un filtro ActiveAdmin sulla pagina di indice, chiamato "by_active_projects", quindi deve mostrare gli utenti che hanno definito il numero di attivi progetti, ovvero progetti che hanno archive == false
. E.g. se digito '2' nel filtro, deve trovare tali account che hanno esattamente 2 progetti attivi.
Per ora ho registrato risorsa "Account" in ActiveAdmin, ed entro admin/account.rb
ho aggiunto filter :by_active_projects_eq
Dopo che ho definito un ambito having_active_projects
per il modello account (modelli/account.rb):
scope :having_active_projects, ->(number) { joins(:projects).where("projects.archive = ?", false).having("count(projects) = ?", number).group("accounts.id") }
fase successiva, ho definito un ransacker per il modello di account in questo modo:
ransacker :by_active_projects, formatter: proc{ |v|
data = Account.having_active_projects(v).map(&:id)
data ||= nil
} do |parent|
parent.table[:id]
end
Nello sviluppo DB c'è un account, che ha esattamente 8 progetti attivi, e il filtraggio funziona alla grande. Ma quando ho provato a filtrare gli account per 2 progetti attivi, ho riscontrato un errore. Nel DB ci sono tre tali conti, e la pagina di errore mi ha riferito che la sintassi di query è sbagliata:
SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114' LIMIT 30 OFFSET 0) subquery_for_count
Come si può vedere, invece di
"accounts"."id" IN ('e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114')
questa cosa viene generato:
"accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114'
ho cercato di scavare nel codice sorgente, muovendosi con i punti sui pezzi di codice all'interno del lib ActiveRecord, ActiveAdmin e Ransack e capito che la relazione è in costruzione con l'aiuto di Arel :: Nodes :: Equality. Non sono sicuro che questo sia il motivo, ma posso dirlo con certezza:
lib/active_record/relation/query_methods.RB `
560 def where!(opts = :chain, *rest)
561 if opts == :chain
562 WhereChain.new(self)
563 else
564 references!(PredicateBuilder.references(opts)) if Hash === opts
565 self.where_values += build_where(opts, rest)
566 self
567 end
568 end`
self
qui è un rapporto Active Record per l'account;
prima di chiamare build_where
sulla riga # 565, self.to_sql
uguale a
SELECT "accounts".* FROM "accounts" WHERE "accounts"."deleted_at" IS NULL ORDER BY "accounts"."created_at" desc
dopo aver chiamato e assegnare il risultato a self.where_values
,
self.to_sql
uguale a
SELECT "accounts".* FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114' ORDER BY "accounts"."created_at" desc
Qualsiasi aiuto o le informazioni sull'argomento sono apprezzate! Grazie!