Mój model produktu zawiera niektóre elementy
Product.first
=> #<Product id: 10, name: "Blue jeans" >
Teraz importuję niektóre parametry produktu z innego zestawu danych, ale w pisowni nazw występują niespójności. Na przykład w innym zbiorze danych Blue jeans
można przeliterować Blue Jeans
.
Chciałem Product.find_or_create_by_name("Blue Jeans")
, ale stworzy to nowy produkt, prawie identyczny z pierwszym. Jakie są moje opcje, jeśli chcę znaleźć i porównać małą literę.
Problemy z wydajnością nie są tu tak naprawdę ważne: jest tylko 100-200 produktów i chcę uruchomić to jako migrację, która importuje dane.
Jakieś pomysły?
ruby-on-rails
activerecord
case-insensitive
Jesper Rønn-Jensen
źródło
źródło
"$##"
i'$##'
. Pierwszy jest interpolowany (podwójne cudzysłowy). Drugi nie jest. Wprowadzane przez użytkownika dane nigdy nie są interpolowane.find(:first)
jest przestarzałe, a teraz można skorzystać z tej opcji#first
. Tak więcProduct.first(conditions: [ "lower(name) = ?", name.downcase ])
model = Product.where('lower(name) = ?', name.downcase).first_or_create
after_create
wProduct
modelu mamy wywołanie zwrotne, a wewnątrz wywołania zwrotnego mamywhere
klauzulę, npproducts = Product.where(country: 'us')
. W takim przypadkuwhere
klauzule są łączone łańcuchowo, gdy wywołania zwrotne są wykonywane w kontekście zakresu. Po prostu dla ciebie.To jest kompletna konfiguracja w Railsach, dla mojego własnego odniesienia. Cieszę się, że ci to pomaga.
Zapytanie:
walidator:
indeks (odpowiedź z unikatowego dla wielkości liter unikalnego indeksu w Rails / ActiveRecord? ):
Żałuję, że nie było piękniejszego sposobu na zrobienie pierwszego i ostatniego, ale z drugiej strony Rails i ActiveRecord są oprogramowaniem typu open source, nie powinniśmy narzekać - możemy to zaimplementować i wysłać prośbę pull.
źródło
find(:first, ...)
obecnie jest on przestarzały, uważam, że jest to najbardziej właściwa odpowiedź.Product.where("lower(name) = ?", name).first
Jeśli korzystasz z Postegres i Rails 4+, masz opcję użycia typu kolumny CITEXT, który pozwoli na zapytania bez rozróżniania wielkości liter bez konieczności zapisywania logiki zapytań.
Migracja:
Aby to przetestować, należy spodziewać się:
źródło
Możesz użyć następujących:
Pamiętaj, że domyślnie jest to ustawienie: case_sensitive => false, więc nie musisz nawet pisać tej opcji, jeśli nie zmieniłeś innych sposobów.
Znajdź więcej na: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of
źródło
W postgresie:
źródło
Kilka komentarzy odnosi się do Arel, bez podania przykładu.
Oto przykład Arel wyszukiwania bez rozróżniania wielkości liter:
Zaletą tego rodzaju rozwiązania jest to, że jest niezależne od bazy danych - użyje poprawnych poleceń SQL dla bieżącego adaptera (
matches
będzie używałILIKE
Postgres iLIKE
wszystkich innych).źródło
Cytowanie z dokumentacji SQLite :
... czego nie wiedziałem, ale to działa:
Więc możesz zrobić coś takiego:
Nie
#find_or_create
, wiem, i może nie jest zbyt przyjazny dla wielu baz danych, ale warto na to spojrzeć?źródło
Innym podejściem, o którym nikt nie wspominał, jest dodawanie wyszukiwarek bez rozróżniania wielkości liter do ActiveRecord :: Base. Szczegóły można znaleźć tutaj . Zaletą tego podejścia jest to, że nie trzeba modyfikować każdego modelu i nie trzeba dodawać
lower()
klauzuli do wszystkich zapytań bez rozróżniania wielkości liter, wystarczy użyć innej metody wyszukiwania.źródło
Wielkie i małe litery różnią się tylko jednym bitem. Najbardziej efektywnym sposobem na ich przeszukanie jest zignorowanie tego bitu, a nie konwersja dolnej lub górnej itp. Zobacz słowa kluczowe
COLLATION
dla MSSQL, sprawdź,NLS_SORT=BINARY_CI
czy używasz Oracle itp.źródło
Find_or_create jest teraz przestarzałe, powinieneś użyć Relacji AR zamiast plus first_or_create, tak jak poniżej:
Zwróci pierwszy dopasowany obiekt lub utworzy go dla ciebie, jeśli nie istnieje.
źródło
Wyszukiwanie bez rozróżniania wielkości liter jest wbudowane w Railsy. Uwzględnia różnice we wdrożeniach baz danych. Użyj wbudowanej biblioteki Arel lub klejnotu, takiego jak Squeel .
źródło
Jest tu wiele świetnych odpowiedzi, szczególnie @ oma's. Ale możesz jeszcze spróbować użyć niestandardowej serializacji kolumn. Jeśli nie przeszkadza ci to, że wszystko jest przechowywane małymi literami w bazie danych, możesz utworzyć:
Następnie w swoim modelu:
Zaletą tego podejścia jest to, że nadal możesz korzystać ze wszystkich zwykłych wyszukiwarek (w tym
find_or_create_by
) bez korzystania z niestandardowych zakresów, funkcji lub posiadanialower(name) = ?
posiadania zapytań.Minusem jest to, że tracisz informacje o obudowie w bazie danych.
źródło
Podobne do Andrewsa, który jest nr 1:
Coś, co zadziałało dla mnie to:
Eliminuje to trzeba zrobić
#where
i#first
w tej samej kwerendy. Mam nadzieję że to pomoże!źródło
Możesz również użyć takich zakresów poniżej, aby wzbudzić ich obawy i uwzględnić w modelach, które mogą ich potrzebować:
scope :ci_find, lambda { |column, value| where("lower(#{column}) = ?", value.downcase).first }
Następnie użyj takiego:
Model.ci_find('column', 'value')
źródło
Zakładając, że używasz mysql, możesz użyć pól, które nie rozróżniają wielkości liter: http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
źródło
źródło
TypeError: Cannot visit Regexp
Niektóre osoby używają LIKE lub ILIKE, ale pozwalają wyszukiwać wyrażenia regularne. Poza tym nie musisz wstawiać w Ruby małej litery. Możesz pozwolić, aby baza danych zrobiła to za Ciebie. Myślę, że może być szybciej. Również
first_or_create
mogą być stosowane powhere
.źródło
Alternatywą może być
źródło
Do tej pory zrobiłem rozwiązanie za pomocą Ruby. Umieść to w modelu produktu:
To da mi pierwszy produkt, w którym pasują nazwy. Lub zero.
źródło