2010-03-12 32 views
5

Tôi muốn để có thể làm Artist.case_insensitive_find_or_create_by_name(artist_name) [1] (và đã cho nó hoạt động trên cả hai sqlite và PostgreSQL)Case-nhạy cảm find_or_create_by_whatever

cách tốt nhất để thực hiện điều này là gì? Ngay bây giờ tôi chỉ thêm một phương pháp trực tiếp đến Artist lớp (loại xấu xí, đặc biệt là nếu tôi muốn chức năng này trong lớp khác, nhưng bất cứ điều gì):

def self.case_insensitive_find_or_create_by_name(name) 
    first(:conditions => ['UPPER(name) = UPPER(?)', name]) || create(:name => name) 
    end 

[1]: Vâng, lý tưởng nó sẽ là Artist.find_or_create_by_name(artist_name, :case_sensitive => false), nhưng điều này có vẻ khó thực hiện hơn

+0

Tại sao 'Artist.find_or_create_by_name (artist_name,: case_sensitive => false)' khó triển khai hơn? –

+1

Nếu bạn sử dụng MySQL, các kết quả khớp không phân biệt chữ hoa chữ thường. –

+0

@KandadaBoggu vì 'find_or_create_by_name' được tạo động bằng' method_missing'? Có thể nó không khó hơn - làm thế nào bạn sẽ thực hiện nó? –

Trả lời

7

câu trả lời này là dành cho những câu hỏi thêm hỏi trong các ý kiến ​​câu hỏi.

Bạn sẽ không thể gọi mặc định find_or_create_by_name nếu bạn ghi đè phương thức đó. Nhưng bạn có thể thực hiện riêng của bạn như hình dưới đây:

def self.find_or_create_by_name(*args) 
    options = args.extract_options! 
    options[:name] = args[0] if args[0].is_a?(String) 
    case_sensitive = options.delete(:case_sensitive) 
    conditions = case_sensitive ? ['name = ?', options[:name]] : 
           ['UPPER(name) = ?', options[:name].upcase] 
    first(:conditions => conditions) || create(options) 
end 

Bây giờ bạn có thể gọi phương thức ghi đè như sau:

User.find_or_create_by_name("jack") 
User.find_or_create_by_name("jack", :case_sensitive => true) 
User.find_or_create_by_name("jack", :city=> "XXX", :zip => "1234") 
User.find_or_create_by_name("jack", :zip => "1234", :case_sensitive => true) 
1

Đã nói về điều này here. Không ai có thể đưa ra giải pháp tốt hơn của bạn :)

5

Bạn phải tạo chỉ mục dựa trên cơ sở dữ liệu.

PostgreSQL

Tạo một chỉ số thấp hơn trường hợp trên artist_name cột.

CREATE INDEX lower_artists_name ON artists(lower(artist_name)) 

mySQL

kiếm là trường hợp nhạy cảm

sqllite

Tạo một chỉ mục trên artist_name cột với tham số đối chiếu

CREATE INDEX lower_artists_name ON artists(artist_name collate nocase) 

Bây giờ bạn có thể sử dụng find_or_create một cách độc lập DB:

find_or_create_by_artist_name(lower(artist_name)) 

Reference

PostgreSQL: Case insensitive search

sqlLite: Case insensitive search

10

Rails 4 cung cấp cho bạn một cách để thực hiện điều tương tự:

Artist.where('lower(name) = ?', name.downcase).first_or_create(:name=>name)

+0

Âm thanh như phương pháp này vẫn tồn tại trong đường ray 4.2 nhưng không được chấp nhận. – Jared

+1

Dường như nó vẫn hoạt động trong đường ray 5.0 mà không có bất kỳ cảnh báo không dùng nữa. Bạn đã thấy phương pháp đó không được chấp nhận ở đâu? –

+0

Tệ của tôi, bạn đã đúng. Tôi chỉ nghĩ rằng nó đã không được chấp nhận vì tôi không thể tìm thấy nó trong tài liệu. Hóa ra nó chỉ là không có giấy tờ. – Jared

Các vấn đề liên quan