Você pode fazer mais do que a comparação em uma data em uma pesquisa do Rails 3?

125

Eu tenho essa pesquisa no Rails 3:

Note.where(:user_id => current_user.id, :notetype => p[:note_type], :date => p[:date]).order('date ASC, created_at ASC')

Mas preciso que a :date => p[:date]condição seja equivalente a :date > p[:date]. Como posso fazer isso? Obrigado pela leitura.

ben
fonte

Respostas:

226
Note.
  where(:user_id => current_user.id, :notetype => p[:note_type]).
  where("date > ?", p[:date]).
  order('date ASC, created_at ASC')

ou você também pode converter tudo na notação SQL

Note.
  where("user_id = ? AND notetype = ? AND date > ?", current_user.id, p[:note_type], p[:date]).
  order('date ASC, created_at ASC')
Simone Carletti
fonte
2
isso é seguro? Quero dizer, se p [: date] veio da entrada do usuário, ele pode causar uma injeção de SQL?
MhdSyrwan
7
É seguro por causa de where(). O uso where()escapa automaticamente da entrada.
Simone Carletti
34
O comentário de Simone não é inteiramente verdadeiro; where()escapa automaticamente a entrada quando é usada no formato mostrado acima com pontos de interrogação no lugar de variáveis, com elas listadas posteriormente na chamada de função. Não é seguro para usá-lo desta maneira:Note.where("date > #{p[:date]}")
bdx
4
Também digno de nota, o uso where("user_id = ?",current_user.id)é mais arriscado do que where(user_id: current_user.id)nos casos em que você mescla modelos que possuem um user_idcampo. Usando os meios de notação SQL matérias que você precisa incluir os esclarecimentos tabela si mesmo, por exemplo: where("notes.user_id = ?",current_user.id).
DreadPirateShawn
1
Você deve ter cuidado com isso, porque o fuso horário. Quando você usa where with "" Rails, vá diretamente ao banco de dados, e no banco de dados a data será salva no UTC, mas você deve estar no UTC + 5, por exemplo, e isso não será corrigido. Assim, garantir para converter o p [data] para a sua UTC atual antes de fazê-lo
Paulo Tarud
70

Se você encontrar problemas em que os nomes das colunas sejam ambíguos, poderá:

date_field = Note.arel_table[:date]
Note.where(user_id: current_user.id, notetype: p[:note_type]).
     where(date_field.gt(p[:date])).
     order(date_field.asc(), Note.arel_table[:created_at].asc())
Sarah Vessels
fonte
2
Por alguma razão, eu estava recebendo um erro quando uma coluna não foi encontrada usando o método "where" de Simone em um servidor PostgreSQL, mas funcionou no SQLite. Seu método funcionou em ambos.
Plackemacher
2

Você pode tentar usar:

where(date: p[:date]..Float::INFINITY)

equivalente em sql

WHERE (`date` >= p[:date])

O resultado é:

Note.where(user_id: current_user.id, notetype: p[:note_type], date: p[:date]..Float::INFINITY).order(:fecha, :created_at)

E eu também mudei

order('date ASC, created_at ASC')

Para

order(:fecha, :created_at)
sesperanto
fonte
0

O Rails 6.1 adicionou uma nova 'sintaxe' para operadores de comparação em wherecondições, por exemplo:

Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)

Portanto, sua consulta pode ser reescrita da seguinte maneira:

Note
  .where(user_id: current_user.id, notetype: p[:note_type], 'date >', p[:date])
  .order(date: :asc, created_at: :asc)

Aqui está um link para o PR, onde você pode encontrar mais exemplos.

Marian13
fonte