2012-01-27 25 views
22

Tôi nghĩ sẽ tốt khi điền vào một trường trạng thái trong một bảng activeRecord bằng cách sử dụng các hằng số. Tuy nhiên, khi nói đến việc kiểm tra xem tình trạng này có một tình trạng cụ thể, tôi đang gặp rắc rối.Cách lưu trữ và so sánh: các biểu tượng trong ActiveRecord (Ruby on Rails)

Nếu tôi làm như sau,

e = Mytable.new 
e.status = :cancelled 
e.save 

sau đó refind kỷ lục và thử và so sánh tình trạng của tôi vào biểu tượng, kiểm tra thất bại. Tôi có một số đầu ra từ giao diện điều khiển để hiển thị điều này.

irb(main):060:0> e.status.eql?("cancelled") 
=> true 
irb(main):061:0> e.status.eql?(:cancelled) 
=> false 
irb(main):062:0> e.status == :cancelled 
=> false 
irb(main):063:0> e.status == "cancelled" 
=> true 
irb(main):064:0> e.status == :cancelled.to_s 
=> true 

Có cách nào tốt hơn để giữ trạng thái trong hồ sơ không? Có cách nào để kiểm tra nếu giá trị trường hiện tại bằng biểu tượng: mà không chuyển đổi ký hiệu: thành chuỗi không? Tôi nghĩ rằng có thể có một nhà điều hành tôi không biết.

+1

ecoologic có một giải pháp tốt cho bạn, nhưng tôi muốn giới thiệu có thể chỉ đạo xa này và có thể làm cho một lớp học với các hằng số trong đó. Bạn có thể làm những việc như 'e.status = Statuses :: CANCELLED' và những gì không. Và nội bộ có thể là một chuỗi và nó không quan trọng. Bạn vẫn đang sử dụng hằng số, và nó sẽ lỗi nếu hằng số đó không tồn tại, và nó sạch hơn theo cách đó. – MrDanA

+0

tại sao bạn không ghi đè lên getter của cột của bạn? – apneadiving

+0

Tôi đã sửa đổi câu trả lời của mình trước khi đọc hai bình luận này nhưng tôi muốn nói rằng tôi yêu giải pháp @MrDanA, bạn nên viết một câu trả lời và tôi sẽ bỏ phiếu! – ecoologic

Trả lời

7

Theo yêu cầu của ecoologic, đây là nhận xét của tôi như một câu trả lời:

ecoologic có một giải pháp tốt cho bạn, nhưng tôi muốn giới thiệu tay lái xa này và làm cho một lớp học với các hằng số trong đó. Bạn có thể làm những việc như e.status = Statuses :: CANCELED. Và nội bộ có thể là một chuỗi và nó không quan trọng. Bạn vẫn đang sử dụng hằng số, và nó sẽ lỗi nếu hằng số đó không tồn tại, và nó sạch hơn theo cách đó.

+0

Như một vấn đề của thực hành tốt nhất, nơi bạn sẽ đặt lớp này? Trong tập tin riêng của nó trong lib, hoặc người trợ giúp? – seanyboy

+0

Tôi đã đặt lớp trạng thái trong tệp mô hình. Nó hoạt động tốt. Tôi cũng đã thêm self.method vào lớp để chuyển đổi trạng thái thành màu. Vì vậy, giữ tất cả những gì ở một nơi. – seanyboy

+1

Tôi thường đặt chúng trong tập tin riêng của họ trong lib, có. Sau đó bạn có thể tự động tải các tập tin (thay vì phải 'yêu cầu 'chúng) bằng cách chỉnh sửa tập tin cấu hình ứng dụng của bạn. – MrDanA

7

Nếu tôi nhớ biểu tượng tốt trong ActiveRecord được lưu trữ ở định dạng yaml, một số loại chuyển đổi phải được thực hiện vì không có biểu tượng nào trong biểu tượng quan hệ (ít nhất tôi biết). Khi bạn đọc nó đó là sau đó một chuỗi đó sẽ không phù hợp với biểu tượng của bạn và thậm chí không phải là chuỗi các biểu tượng, trên thực tế nó phải là một cái gì đó như:

:x # => "--- :x\n" 

Tôi nghĩ rằng plugin này có thể giải quyết vấn đề của bạn, nhưng tôi thiên đường không sử dụng nó một cách trung thực. https://github.com/zargony/activerecord_symbolize

* EDIT *

tôi rời khỏi trên vì tôi nhớ đó là tình hình tôi có và tôi có thể được sửa chữa nếu tôi là sai, tuy nhiên tôi đang cố gắng này ngay bây giờ và lưu trữ giá trị (Rails 3.1.3) là một chuỗi đơn giản với giá trị của biểu tượng, vì vậy sau đây là đủ.

class Example < ActiveRecord::Base 

    def aaa 
    super.to_sym 
    end 

    def aaa=(value) 
    super(value.to_sym) 
    aaa 
    end 

end 

Điều này tất nhiên sẽ buộc giá trị luôn là một biểu tượng

** EDIT SAU TUỔI ** tôi nghĩ rằng nó là tốt trong tình huống này vì nó là rõ ràng rằng trong db đó là một chuỗi và logic là đơn giản, nhưng tôi mạnh mẽ không khuyến khích các phương thức thuộc tính db ghi đè để thêm logic phức tạp hơn.

+1

cũng lưu ý rằng việc sử dụng: to_sym trên đầu vào của người dùng là một ý tưởng tồi: http://www.tricksonrails.com/2010/06/avoid-memory-leaks-in-ruby-rails-code-and-protect-against -denial-of-service/ – oseiskar

+0

yeap, đáng nói đến, đó là thực hành kém – ecoologic

1

Từ lập trình Ruby 1,9, liên quan đến toán tử == trong lớp Symbol (p 729.):

Returns true only if sym and obj are symbols with the same object_id. 

Dù bạn đã lưu trữ trong DB sẽ luôn luôn có object_id khác với object_id cố định biểu tượng (một con trỏ đến một chuỗi chữ, trong trường hợp này).

5

Ngoài ra bạn có thể ghi đè lên reader phương pháp:

def status 
    read_attribute(:status).to_sym 
end 
8

Đây là loại muộn, nhưng có thể giúp người khác.

Nếu bạn có các lớp học với trạng thái khác nhau, bạn có thể xem xét một cách tiếp cận sử dụng hằng cùng với phạm vi như thế này:

class Account < ActiveRecord::Base 
    #------------------------------------------------------------------------------- 
    # Configuration 
    #------------------------------------------------------------------------------- 

    # STATUS is used to denote what state the account is in. 
    STATUS = { :active => 1, :suspended => 2, :closed => 3 } 

    # Scopes 
    scope :active, where(:status => Account::STATUS[:active]) 
    scope :suspended, where(:status => Account::STATUS[:suspended]) 
    scope :closed, where(:status => Account::STATUS[:closed]) 
    ... 
end 

Sau đó, bạn có thể dễ dàng tìm thấy các bản ghi dựa trên uy tín, như vậy:

# get all active accounts 
active_accounts = Consumer.active.all 
# get 50 suspended accounts 
suspended_accounts = Consumer.suspended.limit(50) 
# get accounts that are closed and [some search criteria] 
closed_accounts = Consumer.closed.where([some search criteria]) 

Hy vọng điều này sẽ giúp người khác!

EDIT: Nếu bạn thích sử dụng đá quý, đá quý simple_enum trông giống như một sự thay thế tuyệt vời.

12

Với Rails 4.1.0, bạn có thể muốn sử dụng các enum Active Record.

Để trích dẫn official release notes:

class Conversation < ActiveRecord::Base 
  enum status: [ :active, :archived ] 
end 
  
conversation.archived! 
conversation.active? # => false 
conversation.status  # => "archived" 
  
Conversation.archived # => Relation for all archived Conversations 
  
Conversation.statuses # => { "active" => 0, "archived" => 1 } 
6

Tính đến Rails 4.1, Active Record bây giờ hỗ trợ enums

Từ release notes:

2,5 Active Record enums

Khai báo một thuộc tính enum trong đó các giá trị ánh xạ tới các số nguyên trong cơ sở dữ liệu, nhưng có thể được truy vấn theo tên.

class Conversation < ActiveRecord::Base 
    enum status: [ :active, :archived ] 
end 

conversation.archived! 
conversation.active? # => false 
conversation.status # => "archived" 

Conversation.archived # => Relation for all archived Conversations 

Conversation.statuses # => { "active" => 0, "archived" => 1 } 

Tài liệu bổ sung ở đây: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html

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