2010-09-09 27 views
55

Tôi đang gửi thông số show_all với giá trị true. Giá trị này không được liên kết với một mô hình.Làm cách nào để gửi thông số boolean trong Rails?

điều khiển của tôi là gán tham số này để một biến Ví dụ:

@show_all = params[:show_all] 

Tuy nhiên, @show_all.is_a? String, và if @show_all == true luôn luôn thất bại.

Rails phân tích cú pháp nào làm boolean? Làm thế nào tôi có thể xác định rõ ràng rằng tham số của tôi là một boolean, và không phải là một chuỗi?

+0

Không có những điều như các phép toán luận trong ruby, chỉ 'TrueClass' và' FalseClass' – NullUserException

+1

Rails vẫn con số nó ra automagically khi tham số có liên quan đến một mô hình - nếu kiểu cột trong cơ sở dữ liệu là boolean, nó xử lý tham số dưới dạng 'TrueClass' hoặc' FalseClass'.Bất kỳ ý tưởng làm thế nào tôi có thể làm điều này độc đáo? – nfm

+0

có thể trùng lặp của [Làm thế nào để kiểm tra xem một param là đúng hay sai?] (Http://stackoverflow.com/questions/1711547/how-to-check-if-a-param-is-true-or-false) vì "Có cách nào tốt hơn để làm điều đó nếu/else tuyên bố dựa trên một param là đúng hay sai?" –

Trả lời

61

Tôi muốn nhận xét về câu trả lời zetetic nhưng như tôi có thể' t làm điều đó nhưng tôi sẽ đăng bài này như là một câu trả lời.

Nếu bạn sử dụng

@show_all = params[:show_all] == "1"

sau đó bạn có thể thả ? true : falseparams[:show_all] == "1" tuyên bố bản thân sẽ đánh giá đúng hay sai và do đó điều hành ternary là không cần thiết.

+0

Điểm tốt! Tôi đã cập nhật câu trả lời của mình để phản ánh điều đó. – zetetic

+0

để tham khảo trong tương lai, đây là câu trả lời rõ ràng nhất. Về mặt kỹ thuật, boolean có thể được chuyển thành "true" hoặc "false" nhưng việc truyền một số thì đơn giản hơn vì nó ngăn các lỗi đơn giản như "true" == "True" khi trả về false. Hoặc là 1, hoặc 0. – sybohy

4

Bạn có thể thay đổi tuyên bố bình đẳng của bạn để:

@show_all == "true" 

Nếu bạn muốn nó được một boolean bạn có thể tạo ra một phương thức trên lớp string để chuyển đổi một chuỗi để một boolean.

16
@show_all = params[:show_all] == "1" ? true : false 

Điều này sẽ hoạt động tốt nếu bạn bỏ qua giá trị từ hộp kiểm - một khóa bị thiếu trong giá trị băm tạo ra không, đánh giá sai trong điều kiện.

EDIT

Như đã chỉ ra here, các nhà điều hành ternary là không cần thiết, vì vậy đây chỉ có thể là:

@show_all = params[:show_all] == "1"

0

Bạn có thể chuyển đổi tất cả params boolean của bạn để boolean thực như thế này:

%w(show_all, show_featured).each do |bool_param| 
    params[bool_param.to_sym] = params[bool_param.to_sym] == "true" 
end 

Trong giải pháp này, các thông số bằng không sẽ trở thành sai.

20

Câu hỏi này khá cũ, nhưng kể từ khi tôi gặp vấn đề này một vài lần và không thích bất kỳ giải pháp nào được đề xuất, tôi đã tự hack một số thứ cho phép sử dụng nhiều chuỗi cho đúng chẳng hạn như ' có ',' trên ',' t 'và ngược lại với giả.

khỉ vá các lớp String, và thêm một phương pháp để chuyển đổi chúng sang boolean, và đặt tập tin này trong /config/initializers như đề xuất ở đây: Monkey Patching in Rails 3

class String 
    def to_bool 
    return true if ['true', '1', 'yes', 'on', 't'].include? self 
    return false if ['false', '0', 'no', 'off', 'f'].include? self 
    return nil 
    end 
end 

Chú ý rằng nếu giá trị là không ai trong số những người hợp lệ hoặc cho đúng hay sai, sau đó nó trả về nil. Không giống như tìm kiếm ?paid=false (trả lại tất cả hồ sơ chưa được thanh toán) so với ?paid= (Tôi không chỉ định xem nó có được thanh toán hay không - vì vậy hãy loại bỏ điều này).

Sau đó, sau ví dụ này, logic trong điều khiển của bạn sẽ trông như thế này:

Something.where(:paid => params[:paid].to_bool) unless params[:paid].try(:to_bool).nil? 

Nó khá gọn gàng, và giúp giữ bộ điều khiển/mô hình sạch.

+2

Một giải pháp tuyệt vời, sạch sẽ, gọn gàng và thêm một phần chức năng thực sự hữu ích cho lớp String. Rất đẹp. –

+15

Xin chúc mừng, bây giờ bạn có một 'Chuỗi # to_bool' có thể trả về' nil'. Xin hãy suy ngẫm về điều đó một lúc, và sau đó đổi tên phương thức thành 'String # may_bool?' Hoặc là phương thức 'ArgumentError'. – Nicos

+2

Điều này có thể được đơn giản hóa hơn nữa như 'def to_bool; ['true', '1', 'yes', 'on', 't']. bao gồm? tự; end' – lobati

71

UPDATE: Rails 5:

ActiveRecord::Type::Boolean.new.deserialize('0') 

UPDATE: Rails 4.2 có API công cộng cho việc này:

ActiveRecord::Type::Boolean.new.type_cast_from_user("0") # false 

câu trả lời trước:

ActiveRecord duy trì một danh sách các cơ quan đại diện cho đúng/sai trong https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/column.rb

2.0.0-p247 :005 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("ON") 
2.0.0-p247 :006 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("F") 

Đây không phải là một phần của API công cộng Rails', vì vậy tôi quấn nó thành một phương pháp helper:

class ApplicationController < ActionController::Base 
    private 

    def parse_boolean(value) 
    ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) 
    end 
end 

và thêm một thử nghiệm cơ bản:

class ApplicationControllerTest < ActionController::TestCase 
    test "parses boolean params" do 
    refute ApplicationController.new.send(:parse_boolean, "OFF") 
    assert ApplicationController.new.send(:parse_boolean, "T") 
    end 
end 
+3

chúng ta nên lưu ý rằng 'ActiveRecord :: Type :: Boolean.new.type_cast_from_user (" 0 ")' sẽ trả về 'false' như bạn đã đề cập, nhưng trong Rails 5 nó sẽ bắt đầu trả về true: DEPRECATION CẢNH BÁO: Bạn đã cố gán một giá trị không rõ ràng 'true' hoặc' false' thành cột boolean. Hiện tại giá trị này chuyển thành 'false'. Điều này sẽ thay đổi để phù hợp với ngữ nghĩa của Ruby, và sẽ chuyển sang 'true' trong Rails 5. Nếu bạn muốn duy trì hành vi hiện tại, bạn nên xử lý rõ ràng các giá trị bạn muốn truyền thành' false'. –

+1

'ActiveRecord :: Type :: Boolean' chỉ là một bí danh cho' ActiveModel :: Type :: Boolean'. Nó có thể là một chút tốt hơn để sử dụng lớp gốc. –

1

Tôi nghĩ rằng giải pháp đơn giản nhất là để kiểm tra các tham số "boolean" đối với biểu diễn String của chúng.

@show_all = params[:show_all] 
if @show_all.to_s == "true" 
    # do stuff 
end 

Bất kể Rails có cung cấp thông số là Chuỗi "true" hoặc "false" hoặc TrueClass hoặc FalseClass thực tế hay không, thử nghiệm này sẽ luôn hoạt động.

0

Cách tiếp cận khác là chỉ chuyển khóa mà không có giá trị. Mặc dù sử dụng ActiveRecord::Type::Boolean.new.type_cast_from_user(value) khá gọn gàng, có thể có một tình huống khi ấn định giá trị cho khóa param là dư thừa.

Hãy xem xét những điều sau: Theo chế độ xem chỉ mục sản phẩm của tôi theo mặc định, tôi muốn chỉ hiển thị bộ sưu tập sản phẩm có phạm vi (ví dụ: những sản phẩm có trong kho). Đó là nếu tôi muốn trả lại tất cả các sản phẩm, tôi có thể gửi myapp.com/products?show_all=true và nhập thông số show_all cho giá trị boolean.

Tuy nhiên tùy chọn ngược lại - myapp.com/products?show_all=false chỉ không có ý nghĩa vì nó sẽ trả về cùng một bộ sưu tập sản phẩm như myapp.com/products có thể đã trả lại.

Một thay thế:

nếu tôi muốn trả lại toàn bộ bộ sưu tập unscoped, sau đó tôi gửi myapp.com/products?all và trong điều khiển của tôi xác định

private 

def show_all? 
    params.key?(:all) 
end 

Nếu khóa hiện diện trong params, sau đó bất kể giá trị của nó , Tôi sẽ biết rằng tôi cần phải trả lại tất cả các sản phẩm, không cần phải định giá trị.

0

Bạn có thể thêm dòng sau vào mô hình của bạn:

def show_all= value 
    @show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) 
end 
Các vấn đề liên quan