rails find_by возвращает неверную запись? - PullRequest
0 голосов
/ 24 января 2019

У меня есть приложение, в котором User создает Transaction для покупки Item у другого User. У меня внезапно возникли трудности с find_by в одном методе на Item. Я хочу найти самый первый Transaction, включающий Item, для которого он вызывается, и хочу еще больше ограничить этот результат, выполнив поиск по ряду недопустимых состояний.

class Item < ApplicationRecord
 def first_find
  Transaction.find_by("item_id = ? AND recipient_id = ? AND state != ? OR state != ? OR state != ?", self.id, author.id, :ignored, :declined, :unapproved)
 end
end

Что это делает, несмотря ни на что, возвращает самый первый Transaction в моей базе данных. Это не ожидаемое поведение. Так что в консоли, если я пойду как t = Transaction.last в кеш Transaction id # 5 (который имеет item_id 7 и recipient_id 4), а затем вызову t.item.first_find, я предположительно получу Transaction # 5. Выводом SQL для этого является запрос Transaction Load (1.1ms) SELECT "transactions".* FROM "transactions" WHERE (item_id = 7 AND recipient_id = 4 AND state != 'ignored' OR state != 'declined' OR state != 'unapproved') LIMIT $1 [["LIMIT", 1]].

Что здорово! Это то, что я хочу от вывода. Но, к моему замешательству, он возвращает это:

#<Transaction id: 2, sender_id: 1, recipient_id: 2, item_id: 9 ..... >

Кто-нибудь знает, почему? Спасибо!


Редактировать 1

Так что я думаю, что решил это? У меня была такая проблема раньше, когда введение слишком большого количества параметров поиска в предложение where по какой-то причине портит его.

Так что пока не работает

Transaction.find_by("item_id = ? AND recipient_id = ? AND state != ? OR state != ? OR state != ?", self.id, author.id, :ignored, :declined, :unapproved)

Это делает

Transaction.where("item_id = ? AND recipient_id = ?", self.id, author.id).where("state != ? OR state != ? OR state != ?", :ignored, :declined, :unapproved).first

Хотя я не совсем уверен, почему. Кто-нибудь знает?


Редактировать 2

Операторы AND должны быть отделены от операторов OR.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

отвечая почему.Вот как работает SQL приоритет оператора .Более подробное объяснение здесь .поэтому, когда вы разбиваете его на другое предложение "where", создает новое отношение , которое является результатом фильтрации текущего отношения в соответствии с условиями в аргументах. исходный код здесь .

Позвольте мне показать другие решения.

1.

    Transaction.where(item_id: self.id, recipient_id: author.id).where.not(state: [:ignored, :declined, :unapproved]).first

2.

recipient_transactions = Transaction.where(item_id: self.id, recipient_id: author.id)
active_transactions = Transaction.where.not(state: [:ignored, :declined, :unapproved])
result = recipient_transactions.merge(active_transactions).first # this buils a single query
0 голосов
/ 24 января 2019

Я думаю, что вы должны использовать предложение where вместо использования find_by,

class Item < ApplicationRecord
  def first_find
    Transaction.where("item_id = ? AND recipient_id = ? AND state != ? OR state != ? OR state != ?", self.id, author.id, :ignored, :declined, :unapproved)
  end
end

, это вернет ActiveRecord::Relation (набор записей) вместо одной записи, если вы используете оператор поиска

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...