Mam projekt w Ruby on Rails 4.1.4, stosując activeadmin 1.0.0.pre from git://github.com/activeadmin/activeadmin
, pg 0.17.1
, PostgreSQL 9.3Szyny + ActiveAdmin - filtrowanie z ransacker zgłasza błąd PG :: SyntaxError: error: błąd składni na lub blisko ""
W projekcie mam te modele:
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
Mam zadanie do realizacji filtru ActiveAdmin na stronie indeksu, zwany „by_active_projects”, a więc ma pokazać użytkownikom, że mają określoną liczbę aktywnych projekty, to znaczy takie projekty, które mają archive == false
. E.g. jeśli wpiszę "2" w filtrze, musi znaleźć takie konta, które mają dokładnie 2 aktywne projekty.
Na razie mam zarejestrowaną „Konto” zasobu ActiveAdmin iw ciągu admin/account.rb
Dodałem filter :by_active_projects_eq
Potem już zdefiniowany zakres having_active_projects
dla modelu rachunku (modele/account.rb):
scope :having_active_projects, ->(number) { joins(:projects).where("projects.archive = ?", false).having("count(projects) = ?", number).group("accounts.id") }
Następny krok, ja zdefiniował ransacker dla modelu konta tak:
ransacker :by_active_projects, formatter: proc{ |v|
data = Account.having_active_projects(v).map(&:id)
data ||= nil
} do |parent|
parent.table[:id]
end
W rozwoju DB jest jedno konto, które ma dokładnie 8 aktywnych projektów, a filtrowanie działa świetnie. Ale gdy próbowałem filtrować konta przez 2 aktywne projekty, stanąłem przed błędem. W DB istnieją trzy takie rachunki, a strona błędu poinformował mnie, że składnia zapytanie jest źle:
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
Jak widać, zamiast
"accounts"."id" IN ('e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114')
ta rzecz jest generowany:
"accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114'
Próbowałem zagłębić się w kod źródłowy, poruszając się z punktami przerwania na kawałkach kodu w obrębie bibliotek ActiveRecord, ActiveAdmin i Ransack i odkryłem, że relacja jest tworzona z pomocą Arel :: Węzły :: Równość. Nie jestem pewien, to jest powód, ale jedno mogę powiedzieć na pewno:
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
tutaj jest Active Record relacja na Rachunku;
przed wywołaniem build_where
w wierszu # 565, self.to_sql
równa
SELECT "accounts".* FROM "accounts" WHERE "accounts"."deleted_at" IS NULL ORDER BY "accounts"."created_at" desc
po wywołaniu go i przypisując wynik self.where_values
,
self.to_sql
równa
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
pomocy lub informacje na ten temat są doceniane! Dzięki!