35

Trong Rails 3.1, không thể truy cập biến đối tượng điều khiển trong tệp js.erb hoặc coffee.erb tài sản bằng cú pháp như <% = @foo%>, nơi @foo được đặt trong bộ điều khiển. Vậy thì câu hỏi đặt ra là cách tốt nhất để truyền các biến điều khiển cho tài sản CoffeeScript hoặc JavaScript là gì.Đường ray: truy cập biến đối tượng trong tệp tài liệu CoffeeScript hoặc JavaScript

Câu hỏi này đã được hỏi theo nhiều dạng phức tạp trên diễn đàn, nhưng vấn đề của tôi là hỏi nơi có tất cả các đề xuất được tập hợp lại và mã được cung cấp đơn giản và dễ đọc. Cũng lưu ý rằng tôi đang đề cập cụ thể đến nội dung và không xem tệp phản hồi.

+0

Đây có phải là một bản sao của http://stackoverflow.com/questions/8108511/how-to-access-instance-variables-in-coffeescript-engine-inside-a-slim-template? Có vẻ như câu trả lời được chấp nhận sẽ giúp ích cho bạn. – Thilo

+0

@Thilo Khi tôi hiểu câu hỏi đó đề cập đến mẫu .slim trong thư mục lượt xem, do đó, trong thực tế CoffeeScript đang được xử lý như một phần của chế độ xem thay vì dưới dạng tệp nội dung trước. Nêu tôi sai vui long chân chỉnh tôi. –

+0

Vâng, tôi không quen thuộc với Rails để chắc chắn nếu câu trả lời đó được áp dụng. Nhưng ý chính dường như là làm cho tất cả các biến mẫu mà bạn sẽ cần vào một đoạn Javascript, mà các tài sản khác có thể tham khảo. – Thilo

Trả lời

26

một vài cách tôi đã làm điều này trong quá khứ

đưa các dữ liệu trong các trường ẩn, truy cập dữ liệu trong js/cà phê

# single value 
<%= hidden_field_tag "foo_name", @foo.name, { :id => "foo-name" } %> 
$('#foo-name').val(); 

# when the 'value' has multiple attributes 
<%= hidden_field_tag "foo", @foo.id, { :id => "foo", "data-first-name" => @foo.first_name, "data-last-name" => @foo.last_name } %> 
$foo = $('#foo') 
console.log $foo.val() 
console.log $foo.data("firstName") 
console.log $foo.data("lastName") 

tùy chọn khác: tải dữ liệu vào cấu trúc dữ liệu js trong erb, truy cập nó từ js/coffee

<% content_for(:head) do %> 
    <script> 
    window.App = window.App || {}; 
    window.App.Data = window.App.Data || {}; 
    window.App.Data.fooList = [ 
     <% @list.each do |foo| %> 
      <%= foo.to_json %>, 
     <% end %> 
    ]; 
    </script> 
<% end %> 


# coffee 
for foo in window.App.Data.fooList 
    console.log "#{foo.id}, #{foo.first_name} #{foo.last_name}" 

Tôi không phải là người hâm mộ lớn xây dựng dữ liệu javascript từ ruby ​​trong erb như thế này, điều gì đó về nó chỉ cảm thấy sai - nó có thể có hiệu lực mặc dù

và tùy chọn khác: thực hiện cuộc gọi ajax và lấy dữ liệu theo yêu cầu từ máy chủ

Tôi cũng quan tâm đến ý tưởng khác và phương pháp tiếp cận

+0

Nếu bạn cần chạy các vòng lặp và xây dựng json, bạn có thể sử dụng một before_filter chạy một phương thức để xây dựng một đối tượng JSON và gán nó cho một biến cá thể. Sau đó, bạn chỉ cần tạo một biến mẫu trong lượt gán Javascript của khung nhìn của bạn. Tôi thấy điều này tốt hơn ajax vì nó là một yêu cầu HTTP ít hơn. – BradGreens

+0

Tùy chọn thứ hai trông thực sự tốt. Phải nhớ điều đó. – Donato

8

Có một dàn diễn viên đường sắt thật sự tốt đẹp và khá gần đây (feb. 2012) về chủ đề cụ thể này: #324 Passing Data to JavaScript

Nó hiển thị 3 cách: thẻ tập lệnh, thuộc tính dữ liệu và đá quý Gon. Tôi nghĩ rằng ngôi nhà bao gồm tất cả các kỹ thuật có sẵn. Tôi sẽ chỉ đề cập rằng sử dụng một cuộc gọi AJAX được sử dụng tốt nhất khi bạn có một khối lượng lớn dữ liệu, dữ liệu động hoặc kết hợp cả hai.

+2

Bạn có thể thêm một số mã ví dụ vào câu trả lời của mình không? – rudolph9

+1

Rudolph, mở RailsCast và nó cũng hiển thị các ví dụ mã. Ví dụ tốt hơn tôi có thể cung cấp :) – Max

+1

Tôi đã mở, tôi thấy, nhưng câu trả lời được cho là tự chứa tất cả mã ví dụ thích hợp (nghĩa là _not_ yêu cầu bạn truy cập trang khác để lấy thông tin thích hợp) ... – rudolph9

5

Thay vì sử dụng trường bị ẩn, tôi đã chọn thêm thuộc tính dữ liệu vào div vùng chứa mà jquery có thể nhận.

<div class="searchResults" data-query="<%= @q %>"></div> 

thì jquery để truy cập nó

url: "/search/get_results?search[q]=" + $(".searchResults").data("query") + "&page=" + p 

tôi cảm thấy đây là cách sạch nhất để truyền dữ liệu tới javascript. Sau khi đã tìm thấy không có cách nào để vượt qua một biến đến một tập tin kịch bản cà phê với đường ống tài sản đường ray từ một bộ điều khiển. Đây là phương pháp tôi hiện đang sử dụng. Không thể chờ đợi cho đến khi ai đó thiết lập cách điều khiển với đường ray sẽ là tốt nhất.

3

Trong bộ điều khiển:

@foo_attr = { "data-foo-1" => 1, "data-foo-2" => 2 } 

Trong giao diện (HAML):

#foo{@foo_attr} 

Trong tài sản CoffeeScript:

$("#foo").data("foo-1") 
$("#foo").data("foo-2") 
0

Bạn có thể chỉnh sửa và thêm biến vào params mảng trong bộ điều khiển sau đó truy cập chúng trong response.js.erb.Dưới đây là một ví dụ với params[:value]:

def vote 
    value = params[:type] == "up" ? 1 : -1 
    params[:value] = value 
    @public_comment = PublicComment.find(params[:id]) 

    have_voted = @public_comment.evaluators_for(:pub_votes_up) << @public_comment.evaluators_for(:pub_votes_down) 

    unless have_voted.include?(@current_user) # vote 
    @public_comment.add_or_update_evaluation(:"pub_votes_#{params[:type]}", value, @current_user) 
    else          # unvote 
    @public_comment.delete_evaluation(:"pub_votes_#{params[:type]}", @current_user) 
    params[:value] = 0 
    end 

    respond_to do |format| 
    format.js # vote.js.erb 
    end 
end 

Và đây là một ví dụ đi kèm response.js.erb

button = $('<%= ".pub#{params[:type]}_#{params[:id]}" %>') 
label = button.find('strong') 
<% comment = PublicComment.find(params[:id]) %> 
label.html('<%= comment.reputation_for(:"pub_votes_#{params[:type]}").to_i %>') 

<% if params[:value] == 1 %> 
    button.addClass('btn-success') 
<% elsif params[:value] == -1 %> 
    button.addClass('btn-danger') 
<% else %> 
    if button.hasClass('btn-success') { button.removeClass('btn-success') } 
    if button.hasClass('btn-danger') { button.removeClass('btn-danger') } 
<% end %> 
1

Trong trường hợp dữ liệu javascript của bạn được ra khỏi tay, sử dụng đá quý gon vẫn là cách ưa thích để đi vào đường ray, ngay cả trong năm 2015. Sau khi thiết lập gon, bạn có thể chuyển dữ liệu đến tệp javascript của bạn bằng cách chỉ định dữ liệu cho đối tượng gon trong đường ray.

(Gemfile) 
gem 'gon' 

(controller) 
def index 
    gon.products = Product.all 

(layouts) 
<%= include_gon %> 

(public/javascripts/your_js_can_be_here.js) 
alert(gon.products[0]['id'); 

(html source automatically produced) 
<script> 
    window.gon = {}; 
    gon.products = [{"created_at":"2015", "updated_at":"2015, "id":1, "etc":"etc"}]; 

Bạn có thể đọc chi tiết triển khai chi tiết hơn về Gon hoặc hai kênh rails-javascript khác từ màn hình của Ryan Bate.
http://railscasts.com/episodes/324-passing-data-to-javascript

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