các biến cục bộ tùy chọn trong các mẫu một phần của đường ray: làm thế nào để tôi thoát khỏi mớ hỗn độn (được xác định? foo)?


225

Tôi đã là một đứa trẻ hư và đã sử dụng cú pháp sau trong các mẫu một phần của mình để đặt các giá trị mặc định cho các biến cục bộ nếu một giá trị không được xác định rõ ràng trong hàm băm: cục bộ khi hiển thị một phần -

<% foo = default_value unless (defined? foo) %>

Điều này dường như hoạt động tốt cho đến gần đây, khi (không có lý do gì tôi có thể nhận ra) các biến không được thông qua bắt đầu hành xử như thể chúng được xác định là không (chứ không phải là không xác định).

Như đã được chỉ ra bởi những người hữu ích khác nhau trên SO, http://api.rubyonrails.org/groupes/ActionView/Base.html nói không sử dụng

defined? foo

và thay vào đó để sử dụng

local_assigns.has_key? :foo

Tôi đang cố gắng sửa đổi cách của mình, nhưng điều đó có nghĩa là thay đổi rất nhiều mẫu.

Tôi có thể / nên sạc trước và thực hiện thay đổi này trong tất cả các mẫu không? Có bất kỳ khó khăn tôi cần phải xem? Làm thế nào siêng năng tôi cần phải kiểm tra từng người?

Câu trả lời:


324

Tôi làm việc này:

<% some_local = default_value if local_assigns[:some_local].nil? %>

1
Mặc dù tôi thực sự thích cú pháp nhỏ gọn của gợi ý của hgimenez (ở trên), cách tiếp cận này có lợi thế là rất rõ ràng: điều gì đang xảy ra. (Vẫn có nhược điểm là không cho phép bạn vượt qua con số không như một giá trị cho địa phương)
brahn

1
Trường hợp sử dụng của bạn để muốn vượt qua con số không?
jonnii

Ồ, tôi không có một trường hợp cụ thể trong tâm trí. Chỉ cần cố gắng để hiểu đầy đủ ý nghĩa. Điều này nhắc nhở tôi chấp nhận câu trả lời này :-)
brahn

4
Để khắc phục vấn đề không, tôi đang sao chép mã từ liên kết của OP ( api.rubyonrails.org/groupes/ActionView/Base.html ) <% if local_assigns.has_key? : tiêu đề%> Tiêu đề: <% = tiêu đề%> <% end%> - has_key tránh tình huống không / sai và có thể rút ngắn thành một dòng như câu trả lời ở đây
Phil

5
Vui lòng kiểm tra câu trả lời của Pablo: local_assigns.fetchxử lý hoàn hảo các khóa chẵn với giá trị không. Nó chỉ trả về mặc định nếu khóa không được đặt.
quetzalcoatl

158

local_assignslà một hàm băm, bạn cũng có thể sử dụng tìm nạp với tùy chọn default_value.

local_assigns.fetch :foo, default_value

Điều này sẽ trở lại default_valuenếu fookhông được thiết lập.

CẢNH BÁO:

Hãy cẩn thận local_assigns.fetch :foo, default_valuekhi nào default_valuelà một phương thức, vì dù sao nó cũng sẽ được gọi để truyền kết quả của nó fetch.

Nếu bạn default_valuelà một phương thức, bạn có thể gói nó thành một khối: local_assigns.fetch(:foo) { default_value }để ngăn cuộc gọi của nó khi không cần thiết.


1
Thật đáng để nói một cách rõ ràng: nilcác giá trị được bảo tồn ở đây. Nếu hàm băm chứa :fooánh xạ tới nil, thì fetchnó sẽ trả về nil. Đó là, ít nhất là trên v1.9.3 của tôi. Tôi không nhớ cách cư xử của 1.8.
quetzalcoatl

Điều đó hoàn toàn đúng. Nó nhớ cho tôi vấn đề local_assigns[:foo] || default_value, khi foo trả về giá trị giả, default_valuethay vào đó sẽ được sử dụng. Nó thường là một vấn đề đối với Ghi nhớ @some_value ||= expensive_methodnếu phương thức trả về giá trị giả, nó sẽ luôn được thực thi.
Pablo Cantero

1
Bất cứ ai không hiểu tại sao đây là câu trả lời tốt nhất đã không sử dụng ruby ​​đủ lâu. Bravo Pablo!
mastaBlasta

2
Tối ưu hóa là như sau, do đó bạn chỉ phải gọi điều này một lần ở đầu mẫu, thay vì sử dụng 'bảo vệ tìm nạp' cho mỗi lần sử dụng biến. foo ||= local_assigns[:foo] = local_assigns.fetch(:foo, default_value)
sethcall

Tôi đã tự hỏi tại sao nó không hoạt động, tôi giả sử nó cũng tạo ra biến đó, nhưng chúng tôi vẫn phải sử dụng giá trị trả về:foo = local_assigns.fetch :foo, true
Vadorequest

84

Làm thế nào về

<% foo ||= default_value %>

Điều này nói "sử dụng foonếu nó không phải là không hoặc đúng. Nếu không thì gán default_valuecho foo"


2
Tôi không chắc điều này hoạt động vì foo không được xác định trừ khi nó được chuyển qua hàm băm cục bộ.
jonnii

1
Điều này hoạt động, nhưng nếu bạn có các giá trị mặc định như thế này, có lẽ đó là một dấu hiệu cho thấy bạn nên sử dụng một trình trợ giúp?
psyho

2
Không có phép thuật ở đây. Thêm tài nguyên về chủ đề: Groups.google.com/group/comp.lang.ruby/browse_thread/thread/ Kẻ
hgmnz

37
Tôi thực sự thích phiên bản này vì cú pháp rất nhỏ gọn. Tôi cho rằng nhược điểm lớn là nó có nghĩa là bạn không thể vượt qua con số không hoặc sai làm giá trị cho địa phương, vì nó sẽ bị ghi đè theo mặc định.
brahn

16
@brahn, đó là một điểm tốt. Trong thực tế, điều này nên tránh nếu foolà một boolean. Nó có thể có giá trị của false, và default_valuevô tình bị ghi đè .
hgmnz

10

Tôi nghĩ điều này nên được lặp lại ở đây (từ http://api.rubyonrails.org/groupes/ActionView/Base.html ):

Nếu bạn cần tìm hiểu xem một biến cục bộ nào đó đã được gán một giá trị trong một lệnh gọi kết xuất cụ thể chưa, bạn cần sử dụng mẫu sau:

<% if local_assigns.has_key? :headline %>
  Headline: <%= headline %>
<% end %>

Kiểm tra sử dụng xác định? tiêu đề sẽ không hoạt động. Đây là một hạn chế thực hiện.


6

Trong trường hợp của tôi, tôi sử dụng:

<% variable ||= "" %>

trong phần của tôi
Tôi không biết nếu điều đó tốt nhưng với tôi thì không sao


Điều này thực sự hoạt động khá tốt. Hoạt động cho không xác định và khi đi nilnhư một địa phương trong cuộc gọi một phần là tốt.
Joshua Pinter

3
Ah, đọc xuống bên dưới, điều này sẽ thất bại nếu variablelà một boolean và bạn cần đặt nó thành false. Nó sẽ sử dụng giá trị mặc định thay vì sử dụng falsegiá trị. SỬ DỤNG CÓ NGUY CƠ CỦA RIÊNG BẠN.
Joshua Pinter

5

Tôi biết đó là một chủ đề cũ nhưng đây là đóng góp nhỏ của tôi: tôi sẽ sử dụng local_assigns[:foo].presencetrong một điều kiện bên trong một phần. Sau đó, tôi foochỉ đặt khi cần trong cuộc gọi kết xuất:

<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>

Có một cái nhìn vào hướng dẫn chính thức Rails ở đây . Có hiệu lực từ RoR 3.1.0.


Tôi không thể thấy bất kỳ sự khác biệt thực sự giữa local_assigns[:foo]local_assigns[:foo].presence. Một trong hai sẽ trả về nilnếu khóa không tồn tại trong hàm băm và giá trị nếu nó tồn tại.
jamesmarkcook

1

Tôi nghĩ rằng một tùy chọn tốt hơn cho phép nhiều biến mặc định:

<% options = local_assigns.reverse_merge(:include_css => true, :include_js => true) %>
<%= include_stylesheets :national_header_css if options[:include_css] %>
<%= include_javascripts :national_header_js if options[:include_js] %>

1

Đây là một dẫn xuất của câu trả lời của Pablo. Điều này cho phép tôi đặt mặc định ('đầy đủ') và cuối cùng, 'chế độ' được đặt ở cả local_assigns và một biến cục bộ thực tế.

ham / mỏng:

- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')

erb:

<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>

0

Trực quan và gọn nhẹ hơn:

<% some_local = default_value unless local_assigns[:some_local] %>


3
Tôi nghĩ điều này sẽ thất bại nếu bạn gọi một phần với:locals => {:some_local => false}
brahn

0

Nếu bạn không muốn chuyển biến cục bộ thành một phần mỗi khi bạn gọi nó, bạn làm điều này:

<% local_param = defined?(local_param) ? local_param : nil %>

Bằng cách này bạn tránh được undefined variablelỗi. Điều này sẽ cho phép bạn gọi một phần của bạn có / không có biến cục bộ.


HOẶC local_param = local_param nếu được xác định? (
Local_param

0

Hồng ngọc 2.5

Erb

Điều đó là có thể, nhưng bạn phải khai báo các giá trị mặc định của mình trong phạm vi.

BIẾN từ để thay thế.

# index.html.erb
...
<%= render 'some_content', VARIABLE: false %>
...

# _some_content.html.erb
...
<% VARIABLE = true if local_assigns[:VARIABLE].nil? %>
<% if VARIABLE %>
    <h1>Do you see me?</h1>
<% end %>
...

-6

Một người trợ giúp có thể được tạo ra để trông như thế này:

somearg = opt(:somearg) { :defaultvalue }

Thực hiện như:

module OptHelper
  def opt(name, &block)
    was_assigned, value = eval(
      "[ local_assigns.has_key?(:#{name}), local_assigns[:#{name}] ]", 
      block.binding)
    if was_assigned
      value
    else
      yield
    end
  end
end

Xem blog của tôi để biết chi tiết về cách thức và lý do tại sao.

Lưu ý rằng giải pháp này cho phép bạn vượt qua nil hoặc false làm giá trị mà không bị ghi đè.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.