Rails Model menemukan tempat yang tidak sama


127

Bagaimana saya bisa menemukan catatan di database saya dengan kondisi yang tidak sama? Saya sudah memiliki ini sekarang, tetapi adakah cara yang bagus untuk melakukannya?

GroupUser.where('user_id != ?',me)

Apa yang Anda miliki cukup banyak cara Rails 3 baik untuk melakukannya saya pikir.
Spyros

Jawaban:


229

Dalam Rails 4.x (Lihat http://edgeguides.rubyonrails.org/active_record_querying.html#not-conditions )

GroupUser.where.not(user_id: me)

Di Rel 3.x

GroupUser.where(GroupUser.arel_table[:user_id].not_eq(me))

Untuk mempersingkat panjang, Anda bisa menyimpan GroupUser.arel_tabledalam variabel atau jika menggunakan di dalam model GroupUseritu sendiri misalnya, dalam scope, Anda dapat menggunakan arel_table[:user_id]bukanGroupUser.arel_table[:user_id]

Kredit sintaks Rails 4.0 untuk jawaban @ jbearden


Bagaimana dengan asosiasi? - has_many: group_users, -> {where.not (status: "Decined")}, melalui:: groups, foreign_key: "user_id"
ajbraus

4
Sebagai catatan, ini juga bekerja dengan baik dirantai:GroupUser.where(other_condition: true).where.not(user_id: user_id)
Enrico Carlesso


26

Satu-satunya cara Anda bisa membuatnya lebih menarik adalah dengan MetaWhere .

MetaWhere memiliki sepupu baru yang disebut Squeel yang memungkinkan kode seperti ini:

GroupUser.where{user_id != me}

Tak perlu dikatakan lagi, bahwa jika ini adalah satu-satunya refactor yang akan Anda buat, itu tidak layak menggunakan permata dan saya hanya akan bertahan dengan apa yang Anda dapatkan. Squeel berguna dalam situasi di mana Anda memiliki banyak pertanyaan kompleks yang berinteraksi dengan kode Ruby.


4
MetaWhere memang hebat, tetapi tugas ini bisa dilakukan tanpa menambahkan permata.
tybro0103

1
@ tybro0103 tentu saja tugas dapat dilakukan (dan bagaimana cara OP melakukannya dengan sangat baik), pertanyaannya adalah tentang melakukannya dengan lebih baik. Jadi, jika Anda pikir itu bisa dilakukan lebih mewah tanpa permata, saya akan sangat tertarik bagaimana melakukannya.
Jakub Hampl

Jawaban Vikrant memang memberikan solusi tidak melibatkan sql atau termasuk permata lain. Tapi, saya berdiri teguh, jawaban Anda pasti yang paling ramah-coder / mewah.
tybro0103

1
menambahkan permata untuk menyelesaikan tugas semudah itu. Memukul mozzy dengan bazooka
baash05

Ini berlebihan.
courtimas

23

Rel 4:

Jika Anda ingin menggunakan keduanya tidak sama dan sama, Anda dapat menggunakan:

user_id = 4
group_id = 27
GroupUser.where(group_id: group_id).where.not(user_id: user_id)

Jika Anda ingin menggunakan berbagai operator (mis. >, <), Pada titik tertentu, Anda mungkin ingin beralih notasi ke yang berikut:

GroupUser.where("group_id > ? AND user_id != ?", group_id, user_id)

Bagaimana dengan GroupUser.where(group_id: group_id).where.not(user_id: user_id)?
Enrico Carlesso

@ EnricoCarlesso Terima kasih telah memposting. Saya memperbarui jawaban saya untuk memasukkan saran Anda. Terima kasih.
Rick Smith

9

Anda harus selalu menyertakan nama tabel dalam kueri SQL saat berhadapan dengan asosiasi.

Memang jika tabel lain memiliki user_idkolom dan Anda bergabung dengan kedua tabel, Anda akan memiliki nama kolom yang ambigu dalam kueri SQL (yaitu masalah).

Jadi, dalam contoh Anda:

GroupUser.where("groups_users.user_id != ?", me)

Atau sedikit lebih bertele-tele:

GroupUser.where("#{table_name}.user_id IS NOT ?", me)

Perhatikan bahwa jika Anda menggunakan hash, Anda tidak perlu khawatir tentang itu karena Rails mengurusnya untuk Anda:

GroupUser.where(user: me)

Di Rails 4, seperti yang dikatakan oleh @ dr4k3, metode kueri nottelah ditambahkan:

GroupUser.where.not(user: me)

6

Di Rails 3, saya tidak tahu sesuatu yang lebih menarik. Namun, saya tidak yakin jika Anda sadar, kondisi tidak sama Anda tidak cocok dengan (NAMA pengguna) nilai NULL. Jika Anda menginginkannya, Anda harus melakukan sesuatu seperti ini:

GroupUser.where("user_id != ? OR user_id IS NULL", me)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.